﻿/*----------------------------------------------------------------------------------------
*
*  Copyright 2019, Gao Hai Hui, <fromzeropoint@126.com>.  All rights reserved.
*  https://gitee.com/helloworldghh/xoskit.git
*  Use of this source code is governed by a MIT license
*  that can be found in the License file.
*
----------------------------------------------------------------------------------------*/
#include "../import/head.h"
#include "../macro/head.h"
#include "../impl/head.h"
#include "variant_impl.h"

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 

namespace xos_box
{
    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    static variant_impl::POOL * pool_ptr = 0;

    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    variant_impl::variant_impl()
    {
        init_data();
    }

    variant_impl::~variant_impl()
    {
    }

    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    int variant_impl::get_addr( POOL *** pppPool, LIST *** pppList )
    {
        int ret = 0;
        if( pppPool )
        {
            *pppPool = &pool_ptr;
        }
        if( pppList )
        {
            *pppList = 0;
        }
        return ret;
    }

    int variant_impl::init()
    {
        int ret = 0;
        return ret;
    }

    int variant_impl::term()
    {
        int ret = 0;

        if( ( VT_PROPERTY == m_type ) && m_pProperty && m_bAutoReleaseObject )
        {
            m_pProperty->release();
            m_pProperty = 0;
        }
        else if( ( VT_OBJECT == m_type ) && m_pObject && m_bAutoReleaseObject )
        {
            m_pObject->release();
            m_pObject = 0;
        }
        else if( ( VT_LIST == m_type ) && m_pList && m_bAutoReleaseObject )
        {
            m_pList->release();
            m_pList = 0;
        }

        xos_stl::release_interface( m_pAttr );

        init_data();

        return ret;
    }

    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    const char * variant_impl::to_string( char * lpszValue, int nBufSize, int * lpnSizeNeeded )
    {
        const char * pRet = 0;
        char buf[1024] = { 0 };
        switch( m_type )
        {
        case VT_CREATE_FUNCTION:
            {
                m_str = "create function";
            }
            break;
        case VT_PROPERTY:
            {
                m_str = "property";
            }
            break;
        case VT_LIST:
            {
                m_str = "list";
            }
            break;
        case VT_STRING:
            {
            }
            break;
        case VT_DOUBLE:
            {
                mgr::crt()->sprintf( buf, sizeof( buf ), "%f", m_d );
                m_str = buf;
            }
            break;
        case VT_FLOAT:
            {
                mgr::crt()->sprintf( buf, sizeof( buf ), "%f", m_f );
                m_str = buf;
            }
            break;
        case VT_INT:
            {
                mgr::crt()->sprintf( buf, sizeof( buf ), "%d", m_i );
                m_str = buf;
            }
            break;
        default:
            {
                m_str = "undefined";
            }
            break;
        }
        pRet = m_str.c_str();
        if( lpszValue )
        {
            mgr::crt()->strcpy( lpszValue, nBufSize, pRet );
        }
        if( lpnSizeNeeded )
        {
            *lpnSizeNeeded = ( int )m_str.length() + 1;
        }
        return pRet;
    }

    double variant_impl::to_double( double * lpdValue )
    {
        double ret = 0.0;
        switch( m_type )
        {
        case VT_CREATE_FUNCTION:
        case VT_PROPERTY:
        case VT_LIST:
            {
                m_d = 0.0;
            }
            break;
        case VT_STRING:
            {
                m_d = mgr::crt()->atof( m_str.c_str() );
            }
            break;
        case VT_DOUBLE:
            {
            }
            break;
        case VT_FLOAT:
            {
                m_d = m_f;
            }
            break;
        case VT_INT:
            {
                m_d = m_i;
            }
            break;
        default:
            {
                m_d = 0.0;
            }
            break;
        }
        if( lpdValue )
        {
            *lpdValue = m_d;
        }
        ret = m_d;
        return ret;
    }

    float variant_impl::to_float( float * lpfValue )
    {
        float ret = 0.0f;
        switch( m_type )
        {
        case VT_CREATE_FUNCTION:
        case VT_PROPERTY:
        case VT_LIST:
            {
                m_f = 0.0f;
            }
            break;
        case VT_STRING:
            {
                m_f = ( float )mgr::crt()->atof( m_str.c_str() );
            }
            break;
        case VT_DOUBLE:
            {
                m_f = ( float )m_d;
            }
            break;
        case VT_FLOAT:
            {
            }
            break;
        case VT_INT:
            {
                m_f = ( float )m_i;
            }
            break;
        default:
            {
                m_f = 0.0f;
            }
            break;
        }
        if( lpfValue )
        {
            *lpfValue = m_f;
        }
        ret = m_f;
        return ret;
    }

    int variant_impl::to_int( int * lpnValue )
    {
        int ret = 0;
        switch( m_type )
        {
        case VT_CREATE_FUNCTION:
        case VT_PROPERTY:
        case VT_LIST:
            {
                m_i = 0;
            }
            break;
        case VT_STRING:
            {
                if( 0 == mgr::crt()->strcmp( m_str.c_str(), "false" ) )
                {
                    m_i = 0;
                }
                else if( 0 == mgr::crt()->strcmp( m_str.c_str(), "true" ) )
                {
                    m_i = 1;
                }
                else
                {
                    m_i = mgr::crt()->atoi( m_str.c_str() );
                }
            }
            break;
        case VT_DOUBLE:
            {
                m_i = ( int )m_d;
            }
            break;
        case VT_FLOAT:
            {
                m_i = ( int )m_f;
            }
            break;
        case VT_INT:
            {
            }
            break;
        default:
            {
                m_i = 0;
            }
            break;
        }
        if( lpnValue )
        {
            *lpnValue = m_i;
        }
        ret = m_i;
        return ret;
    }

    int variant_impl::init_data()
    {
        int ret = 0;

        m_bAutoReleaseObject = true;
        m_type = VT_UNKNOWN;

        m_pProperty = 0;
        m_pAttr = 0;
        m_pList = 0;
        m_pObject = 0;
        m_pCreate = 0;

        m_str = "";
        m_d = 0.0;
        m_f = 0.0f;
        m_i = 0;

        m_pCharArray = 0;
        m_nArraySize = 0;
        m_nArrayLen = 0;

        return ret;
    }

    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    const char * variant_impl::str( char * lpszValue, int nBufSize, int * lpnSizeNeeded )
    {
        to_string( 0, 0, 0 );
        if( lpszValue && ( nBufSize > ( int )m_str.length() ) )
        {
            mgr::crt()->strcpy( lpszValue, nBufSize, m_str.c_str() );
        }
        if( lpnSizeNeeded )
        {
            *lpnSizeNeeded = ( int )m_str.length() + 1;
        }
        return m_str.c_str();
    }

    xos::i_release * variant_impl::obj( xos::i_release ** ppv )
    {
        mgr::crt()->assert_valid( VT_OBJECT == m_type );
        if( ppv )
        {
            *ppv = m_pObject;
        }
        return m_pList;
    }

    xos_box::i_list * variant_impl::list( xos_box::i_list ** ppv )
    {
        mgr::crt()->assert_valid( VT_LIST == m_type );
        if( ppv )
        {
            *ppv = m_pList;
        }
        return m_pList;
    }

    i_property * variant_impl::prop( i_property ** ppv )
    {
        mgr::crt()->assert_valid( VT_PROPERTY == m_type );
        if( ppv )
        {
            *ppv = m_pProperty;
        }
        return m_pProperty;
    }

    i_property * variant_impl::attr( i_property ** ppv )
    {
        if( ppv )
        {
            *ppv = m_pAttr;
        }
        return m_pAttr;
    }

    v_create variant_impl::fun( v_create * pv )
    {
        mgr::crt()->assert_valid( VT_CREATE_FUNCTION == m_type );
        if( pv )
        {
            *pv = m_pCreate;
        }
        return m_pCreate;
    }

    double variant_impl::dbl( double * lpdValue )
    {
        to_double( 0 );
        if( lpdValue )
        {
            *lpdValue = m_d;
        }
        return m_d;
    }

    float variant_impl::flt( float * lpfValue )
    {
        to_float( 0 );
        if( lpfValue )
        {
            *lpfValue = m_f;
        }
        return m_f;
    }

    int variant_impl::it( int  * lpnValue )
    {
        to_int( 0 );
        if( lpnValue )
        {
            *lpnValue = m_i;
        }
        return m_i;
    }

    xos::xos_u64 * variant_impl::u64_ptr( xos::xos_u64 ** lppRet )
    {
        if( lppRet )
        {
            *lppRet = m_pu64;
        }
        return m_pu64;
    }

    xos::xos_i64 * variant_impl::i64_ptr( xos::xos_i64 ** lppRet )
    {
        if( lppRet )
        {
            *lppRet = m_pi64;
        }
        return m_pi64;
    }

    xos::xos_u32 * variant_impl::u32_ptr( xos::xos_u32 ** lppRet )
    {
        if( lppRet )
        {
            *lppRet = m_pu32;
        }
        return m_pu32;
    }

    xos::xos_i32 * variant_impl::i32_ptr( xos::xos_i32 ** lppRet )
    {
        if( lppRet )
        {
            *lppRet = m_pi32;
        }
        return m_pi32;
    }

    xos::xos_u16 * variant_impl::u16_ptr( xos::xos_u16 ** lppRet )
    {
        if( lppRet )
        {
            *lppRet = m_pu16;
        }
        return m_pu16;
    }

    xos::xos_i16 * variant_impl::i16_ptr( xos::xos_i16 ** lppRet )
    {
        if( lppRet )
        {
            *lppRet = m_pi16;
        }
        return m_pi16;
    }

    xos::xos_u8 * variant_impl::u8_ptr( xos::xos_u8 ** lppRet )
    {
        if( lppRet )
        {
            *lppRet = m_pu8;
        }
        return m_pu8;
    }

    xos::xos_i8 * variant_impl::i8_ptr( xos::xos_i8 ** lppRet )
    {
        if( lppRet )
        {
            *lppRet = m_pi8;
        }
        return m_pi8;
    }

    char * variant_impl::char_array( char ** lppRet, int * lpnSize, int * lpnLen )
    {
        if( lpnSize )
        {
            *lpnSize = m_nArraySize;
        }
        if( lpnLen )
        {
            *lpnLen = m_nArrayLen;
        }
        if( lppRet )
        {
            *lppRet = m_pCharArray;
        }
        return m_pCharArray;
    }

    char * variant_impl::bin_ptr( char ** lppRet, int * lpnSize, int * lpnLen )
    {
        if( lpnSize )
        {
            *lpnSize = m_nArraySize;
        }
        if( lpnLen )
        {
            *lpnLen = m_nArrayLen;
        }
        if( lppRet )
        {
            *lppRet = m_pBinArray;
        }
        return m_pBinArray;
    }

    double * variant_impl::dbl_ptr( double ** lppRet )
    {
        if( lppRet )
        {
            *lppRet = m_pd;
        }
        return m_pd;
    }

    float * variant_impl::flt_ptr( float ** lppRet )
    {
        if( lppRet )
        {
            *lppRet = m_pf;
        }
        return m_pf;
    }

    bool * variant_impl::bool_ptr( bool ** lppRet )
    {
        if( lppRet )
        {
            *lppRet = m_pbool;
        }
        return m_pbool;
    }


    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    int variant_impl::set( const char * lpszValue )
    {
        m_type = VT_STRING;
        m_str = lpszValue;
        return 0;
    }

    int variant_impl::set_obj( xos::i_release * pv, bool bAutoRelease )
    {
        m_bAutoReleaseObject = bAutoRelease;
        m_type = VT_OBJECT;
        m_pObject = pv;
        return 0;
    }

    int variant_impl::set_list( xos_box::i_list * pv, bool bAutoRelease )
    {
        m_bAutoReleaseObject = bAutoRelease;
        m_type = VT_LIST;
        m_pList = pv;
        return 0;
    }

    int variant_impl::set_prop( i_property * pv, bool bAutoRelease )
    {
        m_bAutoReleaseObject = bAutoRelease;
        m_type = VT_PROPERTY;
        m_pProperty = pv;
        return 0;
    }

    int variant_impl::set_attr( i_property * pv )
    {
        m_pAttr = pv;
        return 0;
    }

    int variant_impl::set( v_create pv )
    {
        m_type = VT_CREATE_FUNCTION;
        m_pCreate = pv;
        return 0;
    }

    int variant_impl::set( double value )
    {
        m_type = VT_DOUBLE;
        m_d = value;
        return 0;
    }

    int variant_impl::set( float value )
    {
        m_type = VT_FLOAT;
        m_f = value;
        return 0;
    }

    int variant_impl::set( int value )
    {
        m_type = VT_INT;
        m_i = value;
        return 0;
    }

    int variant_impl::set( xos::xos_u64 * lpRef )
    {
        m_type = VT_U64_PTR;
        m_pu64 = lpRef;
        return 0;
    }

    int variant_impl::set( xos::xos_i64 * lpRef )
    {
        m_type = VT_I64_PTR;
        m_pi64 = lpRef;
        return 0;
    }

    int variant_impl::set( xos::xos_u32 * lpRef )
    {
        m_type = VT_U32_PTR;
        m_pu32 = lpRef;
        return 0;
    }

    int variant_impl::set( xos::xos_i32 * lpRef )
    {
        m_type = VT_I32_PTR;
        m_pi32 = lpRef;
        return 0;
    }

    int variant_impl::set( xos::xos_u16 * lpRef )
    {
        m_type = VT_U16_PTR;
        m_pu16 = lpRef;
        return 0;
    }

    int variant_impl::set( xos::xos_i16 * lpRef )
    {
        m_type = VT_I16_PTR;
        m_pi16 = lpRef;
        return 0;
    }

    int variant_impl::set_u8( xos::xos_u8 * lpRef )
    {
        m_type = VT_U8_PTR;
        m_pu8 = lpRef;
        return 0;
    }

    int variant_impl::set_i8( xos::xos_i8 * lpRef )
    {
        m_type = VT_I8_PTR;
        m_pi8 = lpRef;
        return 0;
    }

    int variant_impl::set_char_array( char * lpRef, int nBufSize )
    {
        m_type = VT_CHAR_ARRAY;
        m_pCharArray = lpRef;
        m_nArraySize = nBufSize;
        m_nArrayLen = 0;
        return 0;
    }

    int variant_impl::set_bin( char * lpRef, int nBufSize )
    {
        m_type = VT_BIN_PTR;
        m_pBinArray = lpRef;
        m_nArraySize = nBufSize;
        m_nArrayLen = 0;
        return 0;
    }

    int variant_impl::set( double * lpRef )
    {
        m_type = VT_DOUBLE_PTR;
        m_pd = lpRef;
        return 0;
    }

    int variant_impl::set( float * lpRef )
    {
        m_type = VT_FLOAT_PTR;
        m_pf = lpRef;
        return 0;
    }

    int variant_impl::set( bool * lpRef )
    {
        m_type = VT_BOOL_PTR;
        m_pbool = lpRef;
        return 0;
    }

    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    i_variant::VT_TYPE variant_impl::get_type( i_variant::VT_TYPE * lpType )
    {
        return m_type;
    }

    int variant_impl::set_type( i_variant::VT_TYPE type )
    {
        m_type = type;
        return 0;
    }

    int variant_impl::set_ref_value( i_variant * pVT )
    {
        mgr::crt()->assert_valid( VT_STRING == pVT->get_type( 0 ) );

        switch( m_type )
        {
        case VT_CHAR_ARRAY:
            {
                const char * pRet = 0;
                int nLen = 0;
                pRet = pVT->str( 0, 0, &nLen );
                mgr::crt()->strcpy( m_pCharArray, m_nArraySize, pRet );
                m_nArrayLen = nLen;
            }
            break;
        case VT_BIN_PTR:
            {
                const char * pRet = 0;
                int nLen = 0;
                pRet = pVT->str( 0, 0, &nLen );
                mgr::crt()->memcpy( m_pBinArray, pRet, nLen );
                m_nArrayLen = nLen;
            }
            break;
        case VT_DOUBLE_PTR:
            {
                *m_pd = pVT->dbl();
            }
            break;
        case VT_FLOAT_PTR:
            {
                *m_pf = pVT->flt();
            }
            break;
        case VT_BOOL_PTR:
            {
                const char * pRet = pVT->str( 0, 0, 0 );
                if( 0 == mgr::crt()->stricmp( pRet, "true" ) )
                {
                    *m_pbool = true;
                }
                else
                {
                    *m_pbool = false;
                }
            }
            break;
        case VT_U64_PTR:
            {
                *m_pu64 = ( xos::xos_u64 )pVT->dbl();
            }
            break;
        case VT_I64_PTR:
            {
                *m_pi64 = ( xos::xos_i64 )pVT->dbl();
            }
            break;
        case VT_U32_PTR:
            {
                *m_pu32 = ( xos::xos_u32 )pVT->it();
            }
            break;
        case VT_I32_PTR:
            {
                *m_pi32 = ( xos::xos_i32 )pVT->it();
            }
            break;
        case VT_U16_PTR:
            {
                *m_pu16 = ( xos::xos_u16 )pVT->it();
            }
            break;
        case VT_I16_PTR:
            {
                *m_pi16 = ( xos::xos_i16 )pVT->it();
            }
            break;
        case VT_U8_PTR:
            {
                *m_pu8 = ( xos::xos_u8 )pVT->it();
            }
            break;
        case VT_I8_PTR:
            {
                *m_pi8 = ( xos::xos_i8 )pVT->it();
            }
            break;
        default:
            {
            }
            break;
        }

        return 0;
    }

} // xos_common
